﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Manul.Genetics.Genom;

namespace Manul.Genetics.Compiler
{
    public class GenomCompiler
    {
        public static GenomCompilationError CheckEpistasisLoop(Character.Character characterContainer, Character.Character characterToAdd)
        {
            List<Character.Character> charactersList = new List<Manul.Genetics.Character.Character>();
            charactersList.Add(characterToAdd);
            int i = 0;
            do
            {
                if (charactersList[i].Epistasis.Contains(characterContainer))
                {
                    return new GenomCompilationError(
                        String.Format(GenomCompilationErrorText.GetErrorText(
                                        GenomCompilationErrorType.EpistasisLoop),
                                            charactersList[i].Name,
                                            characterToAdd.Name),
                        GenomCompilationErrorType.EpistasisLoop);
                }
                else
                {
                    foreach(Character.Character characterToReview in charactersList[i].Epistasis)
                        if (!charactersList.Contains(characterToReview))
                            charactersList.Add(characterToReview);
                }
            } while (i < charactersList.Count);
            return GenomCompilationError.Null;
        }

        public static List<CompilationResult> Compile(GenomData genomData, Character.Character character)
        {
            bool IsCompiled = true;
            List<CompilationResult> compilationResults = new List<CompilationResult>();
            StringBuilder codeSearch = new StringBuilder();
            bool IsSuccessfull = false;
            if (!String.IsNullOrEmpty(character.Code))
            {
                StringBuilder stringBuilder = new StringBuilder(character.Code);
                while (stringBuilder.Length > 0)
                {
                    if (stringBuilder[0] == '?')
                    {
                        stringBuilder.Remove(0, 1);
                        continue;
                    }
                    int position = stringBuilder.Length;
                    codeSearch = new StringBuilder(stringBuilder.ToString());
                    IsSuccessfull = false;
                    while (codeSearch.Length > 0)
                    {
                        Gen genItem = genomData.GenomValues.FindGen(codeSearch.ToString());
                        if (genItem != Gen.Null)
                        {
                            compilationResults.Add(new CompilationResult(genItem));
                            stringBuilder.Remove(0, codeSearch.Length);
                            IsSuccessfull = true;
                            break;
                        }
                        else
                        {
                            codeSearch.Remove(codeSearch.Length - 1, 1);
                        }
                    }
                    if (!IsSuccessfull)
                        break;
                }
                if (!IsSuccessfull)
                {
                    compilationResults.Add(new CompilationResult(
                            new GenomCompilationError(String.Format(GenomCompilationErrorText.GetErrorText(
                                GenomCompilationErrorType.WrongCode), stringBuilder.ToString()),
                                GenomCompilationErrorType.WrongCode)));
                    IsCompiled = false;
                }
            }
            //Check locuses count
            List<Locus> locuses = new List<Locus>();
            List<GenomDirectory> directories = new List<GenomDirectory>();
            directories.Add(genomData.GenomValues);
            int i = 0;
            while(i < directories.Count)
            {
                foreach(GenomItem genomItem in directories[i].GenomItems)
                {
                    if (genomItem is GenomDirectory)
                        directories.Add(genomItem as GenomDirectory);
                    else if (genomItem is Locus)
                        locuses.Add(genomItem as Locus);
                }
                i++;
            }
            foreach (Locus locusItem in locuses)
            {
                int gensIncluded = 0;
                foreach (Gen genItem in locusItem.Gens)
                {
                    CompilationResult compilationResult = compilationResults.FirstOrDefault(e => e.IsSuccessfull && (e.GenItem == genItem));
                    if (compilationResult != null)
                        gensIncluded++;
                }
                if (gensIncluded > locusItem.Capacity)
                {
                    compilationResults.Add(new CompilationResult(
                        new GenomCompilationError(String.Format(GenomCompilationErrorText.GetErrorText(
                            GenomCompilationErrorType.LocusOverload), locusItem.Name, locusItem.Capacity),
                            GenomCompilationErrorType.LocusOverload)));
                    IsCompiled = false;
                }
            }
            character.IsCompiled = IsCompiled;
            return compilationResults;
        }
    }
}
